public class Test {
    public static void main2(String[] args) {
        StringBuffer strBuf=new StringBuffer("How are you today?");
        System.out.println(strBuf);//How are you today?

        //String 的对象是不可变的 当我们用 + 拼接多个字符串时 底层就调用了StringBuffer 和 StringBuilder
        strBuf.append(" and What can I do for you?");
        System.out.println(strBuf);//How are you today? and What can I do for you?
        //拼接好后又返回一个 新的 String 对象 所以在需要频繁拼接字符串时 用 String 效率会十分底下

        //在 Java 中 String 是一个不可变的字符序列 即一旦创建就不能再更改它的值
        //而 StringBuffer 和 StringBuilder 类是可变的字符序列 可以在其中进行插入、删除和修改等操作

        //String 与 StringBuffer 和 StringBuilder 的区别
        //1.可变性：String 对象被创建后是不可改变的 而 StringBuffer 和 StringBuilder 是可变的
        //2.线程安全：String 是不可变的 所有对 String 的操作都是线程安全的 而 StringBuffer 是线程安全的 StringBuilder 是非线程安全的
        //3.性能：由于 String 是不可变的 所以每次对 String 对象进行修改其实都是创建了一个新的 String 对象
        //       而 StringBuffer 和 StringBuilder 可以在原有对象上进行修改 从而避免了对象创建和销毁的开销 因此在频繁修改时性能更优
        //
        //综上所述 如果需要进行频繁的字符串操作 特别是涉及到并发操作的场景 应该使用 StringBuffer
        //如果不涉及并发操作 可以使用 StringBuilder 来获得更好的性能 而如果需要一个不可变的字符串对象 可以使用 String

        StringBuilder strBui=new StringBuilder(strBuf);
        System.out.println("strBui: "+strBui);//strBui: How are you today? and What can I do for you?
        strBui.reverse();//逆置
        System.out.println("strBui reverse: "+strBui);//strBui reverse: ?uoy rof od I nac tahW dna ?yadot uoy era woH
    }

    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hello";
        String s3 = new String("hello");
        String s4 = new String("hello");
        System.out.println(s1 == s2);//true
        System.out.println(s3 == s4);//false
        System.out.println(s1 == s3);//false
        // 为啥s1 等于 s2 但 s3 != s4 s1 != s3 ?

        //这时候就需要通过常量池(String Table) 来解释了(常量池在堆区)
        //在实例化s1 时 构造了一个 string 对象 并将其对应的哈希值 (并不是String类当中的hash) 存放到常量池当中
        //当实例化s2 时 首先通过 {'h','e','l','l','o'} 对应的哈希值 在常量池中查找 是否存在这个对象 存在直接返回其引用(若不存在就像s1那样)
        //所以 s1 == s2 为 true
        //但 s3 s4 的实例化就不一样了 不管三七二十一 编译器都将在堆区创建这个两个类
        //随后再看 常量池中 是否存在 {'h','e','l','l','o'} 这个字符串数组 存在就将 s3 s4 中的 value;
        //设置为这个字符串的引用
        //故 s3 s4 不相等 也不等于 s1

        //可通过 intern 将 String 对象添加到常量池当中
        char[] chars={'h','i'};
        String str1 = new String(chars);
        str1.intern();
        String str2 = "hi";
        System.out.println(str1 == str2);//true

        /*public final class String
          private final byte[] value;*/

        //字符串的不可变性 是由于 java String 这个类中 的 value 是 private 并且
        //没有提供 setValue 这个方法 所以说字符串是不可变的 并不是 String 这个类 被 final 修饰的原因
    }
}
